<script>

  function deepClone(origin, target, hash = new WeakMap()) {
    target = target || {};

    if (origin === null) return origin;
    if (origin instanceof Date) return new Date(origin);
    if (origin instanceof RegExp) return new RegExp(origin);
    if (typeof (origin) !== 'object') return origin;

    //  防止对象中的循环引用爆栈，把拷贝过的对象直接返还即可
    if (hash.has(origin)) return hash.get(origin);
    hash.set(origin, target)  // 制作一个映射表


    const toString = Object.prototype.toString;

    function copyFn(fn) {
      const result = eval("0," + fn);
      for (const prop in fn) {
        deepClone(fn[prop], result[prop], hash)
      }
      return result
    }

    const props = Object.getOwnPropertyNames(origin);
    props.forEach(prop => {
      if (!origin.hasOwnProperty(prop)) return;
      const current = origin[prop];
      const type = typeof (current);

      if (type === 'object' && current !== null) {
        const objType = toString.call(current);
        if (objType === '[object Object]') {
          target[prop] = {};
          deepClone(current, target[prop], hash);
        } else if (objType === '[object Array]') {
          target[prop] = [];
          deepClone(current, target[prop], hash);
        } else if (current instanceof Date) {
          target[prop] = new Date(current);
        } else if (current instanceof RegExp) {
          target[prop] = new RegExp(current);
        }
      } else if (type === 'function') {
        target[prop] = copyFn(current);
      } else {
        target[prop] = current;
      }
    })

    //处理symbol类型
    const symKeys = Object.getOwnPropertySymbols(origin);
    if (symKeys.length) {
      symKeys.forEach(symKey => {
        target[symKey] = origin[symKey];
      });
    }
    return target;
  }

  let s1 = Symbol('s1');

  let obj = {
    a: '100',
    b: undefined,
    c: null,
    d: Symbol(2),
    e: /^\d+$/,
    f: new Date,
    g: true,
    arr: [10, 20, 30],
    school: {
      name: 'cherry',
      [s1]: 's1'
    },
    fn: function fn() {
      console.log('fn');
    }
  }

  obj.h = obj;
  let obj2 = deepClone(obj);

  obj.a = '101';
  obj.arr[0] = 11;
  obj.school.name = 'ly';
  obj.d = Symbol(1);
  obj.f = Date.now();
  obj.fn.a = 123213;

  console.log(obj);

  console.log(obj2);
</script>